package com.sunlands.zlcx.usercenter.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class CalendarUtil {
    private static final Logger log = LoggerFactory.getLogger(CalendarUtil.class);
    public static final String CREDIT_CARD_DATE_FORMAT = "MM/yyyy";
    public static final String SHORT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String SHORT_DATE_FORMAT_YYYY_MM = "yyyy-MM";
    public static final String SHORT_DATE_DOT_FORMAT = "yyyy.MM.dd";
    public static final String SHORT_DATE_FORMAT_NO_DASH = "yyyyMMdd";
    public static final String SIMPLE_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String SIMPLE_DATE_FORMAT_NO_DASH = "yyyyMMddHHmmss";
    public static final String LOG_DATE_FORMAT = "yyyyMMdd_HH00";
    public static final String ZONE_DATE_FORMAT = "EEE yyyy-MM-dd HH:mm:ss zzz";
    public static final String DATE_FORMAT = "yyyy/MM/dd EEE";
    public static final String TIME_FORMAT = "HH:mm";
    public static final String SHORT_DATA_FORMAT_YYYY_MMDD = "yyyy/MMdd";
    public static final String TIME_FULL_FORMAT = "HH:mm:ss";

    public static int daysBetween(Calendar startTime, Calendar endTime) {
        if (startTime == null) {
            throw new IllegalArgumentException("startTime is null");
        }
        if (endTime == null) {
            throw new IllegalArgumentException("endTime is null");
        }
        if (startTime.compareTo(endTime) > 0) {
            throw new IllegalArgumentException("endTime is before the startTime");
        }
        return (int) ((endTime.getTimeInMillis() - startTime.getTimeInMillis()) / (1000 * 60 * 60 * 24));
    }

    /**
     * 通过时间秒毫秒数判断两个时间的间隔天数
     * @param date1
     * @param date2
     * @return
     */
    public static int diffDaysByDate(Date date1,Date date2)
    {
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000*3600*24));
        return days;
    }

    public static Calendar startOfDayTomorrow() {
        Calendar calendar = Calendar.getInstance();
        truncateDay(calendar);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        return calendar;
    }

    /**
     * create a calendar for start of day yesterday.
     * 
     * @return
     */
    public static Calendar startOfDayYesterday() {
        Calendar yesterday = Calendar.getInstance();
        truncateDay(yesterday);
        yesterday.add(Calendar.DAY_OF_MONTH, -1);
        return yesterday;
    }

    /**
     * Truncate the calendar's Calendar.HOUR, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND to ZERO.
     * 
     * @param calendar
     * @return
     */
    public static Calendar truncateDay(Calendar calendar) {
        if (calendar == null) {
            throw new IllegalArgumentException("input is null");
        }
        calendar.set(Calendar.AM_PM, Calendar.AM);
        calendar.set(Calendar.HOUR, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar;
    }

    /**
     * format a calendar using {@link SimpleDateFormat}, with default pattern. if a null calendar is passed
     * in, empty string is returned.
     * 
     * @param calendar
     * @return
     */
    public static String format(Calendar calendar) {
        String formatted = "";
        if (calendar != null) {
            formatted = new SimpleDateFormat().format(calendar.getTime());
        }
        return formatted;
    }

    /**
     * format a Time using {@link SimpleDateFormat}, with default pattern. if a null calendar is passed in,
     * empty string is returned.
     * 
     * @param time
     * @return
     */
    public static String format(Time time) {
        String formatted = "";
        if (time != null) {
            formatted = new SimpleDateFormat(TIME_FORMAT).format(time.getTime());
        }
        return formatted;
    }

    /**
     * Return the String representation of the Calendar against the given format.
     * 
     * @param calendar the date to format, such as 'yyyy-MM-dd HH:mm:ss' for long date format with 24H
     * @param format the date format pattern
     * @return the format Date String.
     */
    public static String getDateString(Calendar calendar, String format) {
        if (calendar == null) {
            return null;
        }
        return getDateString(calendar.getTime(), format);
    }

    /**
     * 获得默认格式化时间 'yyyy-MM-dd HH:mm:ss'
     * 
     * @param date
     * @return
     */
    public static String getDefaultDateString(Date date) {
        if (null == date) {
            return "";
        }
        return getDateString(date, SIMPLE_DATE_FORMAT);
    }

    /**
     * 获得默认格式化时间 'yyyy-MM-dd'
     * 
     * @param date
     * @return
     */
    public static String getShortDateString(Date date) {
        if (null == date) {
            return "";
        }
        return getDateString(date, SHORT_DATE_FORMAT);
    }
    
    /**
     * 根据自定义格式获取时间
     * @param date
     * @param format
     * @return
     */
    public static String getFormatDateString(Date date, String format) {
        if (null == date) {
            return "";
        }
        return getDateString(date, format);
    }

    /**
     * 获得默认格式化时间 'yyyyMMdd'
     *
     * @param date
     * @return
     */
    public static String getFormatDateToString(Date date) {
        if (null == date) {
            return "";
        }
        return getDateString(date, SHORT_DATE_FORMAT_NO_DASH);
    }

    /**
     * Return the String representation of the Date against the given format.
     * 
     * @param date the date to format
     * @param format the date format pattern
     * @return the format Date String.
     */
    public static String getDateString(Date date, String format) {
        if (date == null) {
            return null;
        }

        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * Return the String representation of the Date against the given format.
     * 
     * @param date the date to format
     * @param format the date format pattern
     * @return the format Date String.
     */
    public static String getDateString(Date date, String format, Locale locale) {
        if (date == null) {
            return null;
        }

        SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
        return sdf.format(date);
    }

    /**
     * Parses the <tt>Date</tt> from the given date string and the format pattern.
     * 
     * @param dateString
     * @param pattern the date format
     * @throws {@link IllegalArgumentException} if date format error
     * @return
     */
    public static Date parseDate(String dateString, String pattern) {
        Date date = null;
        try {
            DateFormat format = new SimpleDateFormat(pattern);
            date = format.parse(dateString);
        } catch (ParseException ex) {
            log.error("Invalid date string: " + dateString, ex);
            throw new IllegalArgumentException("Invalid date string: " + dateString, ex);
        }

        return date;
    }

    /**
     * 将string转换成date类型数据
     * 
     * @param dateString
     * @return
     */
    public static Date parseDefaultDate(String dateString) {
        if (!StringUtils.hasText(dateString)) {
            return null;
        }
        Date date = null;
        try {
            DateFormat format = new SimpleDateFormat(SIMPLE_DATE_FORMAT);
            date = format.parse(dateString);
        } catch (ParseException ex) {
            log.error("Invalid date string: " + dateString, ex);
            throw new IllegalArgumentException("Invalid date string: " + dateString, ex);
        }

        return date;
    }
    
    public static Date parse(String str, String pattern, Locale locale) {
      if(str == null || pattern == null) {
          return null;
      }
      try {
          return new SimpleDateFormat(pattern, locale).parse(str);
      } catch (ParseException e) {
          log.error(e.getMessage());
      }
      return null;
  }
    

    public static Calendar parseCalendarShort(String dateString) {
        if (!StringUtils.hasText(dateString)) {
            return null;
        }
        return parseCalendar(dateString, SHORT_DATE_FORMAT);
    }

    public static Calendar parseCalendar(String dateString) {
        if (!StringUtils.hasText(dateString)) {
            return null;
        }
        return parseCalendar(dateString, SIMPLE_DATE_FORMAT);
    }

    /**
     * int 转时间
     * 
     * @param time
     * @return
     */
    public static String parseIntegerToDate(Integer time) {
        if(time ==null){
            return "00:00";
        }
        StringBuilder sb = new StringBuilder("");
        int xs = time / 3600;
        if(xs>0){
        if (xs < 10) {
            sb.append("0");
        }
        
        sb.append(xs);
        sb.append(":");
        }
        int fen = (time - 3600 * xs) / 60;
        if (fen < 10) {
            sb.append("0");
        }
        sb.append(fen);
        sb.append(":");
        int second = time - xs * 3600 - fen * 60;
        if (second < 10) {
            sb.append("0");
        }
        sb.append(second);
        return sb.toString();
    }

    /**
     * Parses the <tt>Date</tt> from the given date string and the format pattern and return it as a
     * {@link Calendar} instance.
     * 
     * @param dateString
     * @param pattern the date format
     * @throws {@link IllegalArgumentException} if date format error
     * @return
     */
    public static Calendar parseCalendar(String dateString, String pattern) {
        Date date = parseDate(dateString, pattern);

        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c;
    }

    /**
     * Parses the <tt>Date</tt> from the given date string with the format pattern 'yyyy-MM-dd'.
     * 
     * @param dateString
     * @throws {@link IllegalArgumentException} if date format error
     * @return
     */
    public static Date parseShortDate(String dateString) {
        if (!StringUtils.hasText(dateString)) {
            return null;
        }
        Date date = null;
        try {
            DateFormat format = new SimpleDateFormat(SHORT_DATE_FORMAT);
            date = format.parse(dateString);
        } catch (ParseException ex) {
            log.error("Invalid date string: " + dateString, ex);
            throw new IllegalArgumentException("Invalid date string: " + dateString, ex);
        }

        return date;
    }

    /**
     * return one day before the given date.
     * 
     * @param date the given date
     * @return the adjusted date.
     */
    public static Calendar backOneDay(Calendar date) {
        Calendar cal = (Calendar) date.clone();
        cal.add(Calendar.DATE, -1);
        return cal;
    }

    /**
     * Get how many days in current month.
     */
    public static int daysForCurrentMonth() {
        Calendar c = Calendar.getInstance();
        int days = c.getActualMaximum(Calendar.DAY_OF_MONTH);

        return days;
    }

    /**
     * Return the Calendar for the give date.
     * 
     * @param date
     * @return
     */
    public static Calendar fromDate(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);

        return c;
    }

    /**
     * return the EPOCH = "1970-01-01 00:00:00"
     * 
     * @return
     */
    public static Calendar epoch() {

        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(0);
        return c;
    }

    public static long getSimpleDateTimeMillis(long timeMillis) {
        Date date = new Date(timeMillis);
        String dateStr = getDateString(date, SHORT_DATE_FORMAT);
        Date transformDate = parseDate(dateStr, SHORT_DATE_FORMAT);
        return transformDate.getTime();
    }

    /**
     * get the date from a day with days
     * 
     * @author <a href="mailto:wang-shuai@letv.com">Ousui</a>
     * @param from which day
     * @param days interval days, 0: today; positive: future; negative: history.
     * @return
     */
    public static Calendar getDateFromDate(Date from, long days) {
        long froml = from.getTime();
        // 时间间隔。
        long interval = days * 24L * 60L * 60L * 1000L;
        long millis = froml + interval;
        Calendar now = Calendar.getInstance();
        now.setTimeInMillis(millis);
        return now;
    }

    /**
     * get the date from a day with days
     * 
     * @author <a href="mailto:wang-shuai@letv.com">Ousui</a>
     * @param from which day
     * @param days interval days, 0: today; positive: future; negative: history.
     * @return String
     */
    public static String getDateFromDate(Date from, long days, String format) {
        Calendar c = CalendarUtil.getDateFromDate(from, days);
        return CalendarUtil.getDateString(c, format);
    }

    public static String getDateFromDate(String from, long days, String format) {
        Date d = CalendarUtil.parseDate(from, format);
        Calendar c = CalendarUtil.getDateFromDate(d, days);
        return CalendarUtil.getDateString(c, format);
    }

    public static Calendar getDayStart() {
        Calendar cal = Calendar.getInstance();
        cal = truncateDay(cal);
        return cal;
    }
    
    public static Date getDayBegin(){
    	return parseDate(getShortDateString(new Date())+" 00:00:00", SIMPLE_DATE_FORMAT);
    }

    public static Calendar getWeekDayStart() {
        Calendar cal = Calendar.getInstance();
        int day_of_week = cal.get(Calendar.DAY_OF_WEEK) - 2;
        cal.add(Calendar.DATE, -day_of_week);
        cal = truncateDay(cal);
        return cal;
    }

    public static Calendar getMonthDayStart() {
        Calendar cal = Calendar.getInstance();
        int day_of_month = cal.get(Calendar.DAY_OF_MONTH) - 1;
        cal.add(Calendar.DATE, -day_of_month);
        cal = truncateDay(cal);
        return cal;
    }
    
    /**
     * n为正数时：返回n天以后的date
     * n为负数时：返回n天以前的date
     */
    public static Date addOrBeforeNDay(Date date, int n) {
        if (null == date) {  
            return date;  
        }  
        Calendar c = Calendar.getInstance();
        c.setTime(date);   //设置当前日期  
        c.add(Calendar.DATE, n); //日期加n天
        date = c.getTime();  
        return date;  
    }

    public static String dateBetween(Date btime, Date etime){
        if(btime == null || etime == null){
            return "";
        }
        return CalendarUtil.dateBetween(btime.getTime(),etime.getTime());
    }

    public static String dateBetween(Long btime, Long etime){
        StringBuilder sb = new StringBuilder("");
        if(btime == null || etime == null){
            return "00:00";
        }
        long between = etime-btime;
        if(between < 0){
            return "00:00";
        }
        long day = between / (24 * 60 * 60 * 1000);
        long hour = (between / (60 * 60 * 1000) - day * 24);
        long min = ((between / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long s = (between / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        long ms = (between - day * 24 * 60 * 60 * 1000 - hour * 60 * 60 * 1000 - min * 60 * 1000 - s * 1000);
        if(day != 0){
            sb.append(day+"天");
        }
        if(hour != 0){
            sb.append(hour+"小时");
        }
        if(min != 0){
            sb.append(min+"分");
        }
        if(s != 0){
            sb.append(s+"秒");
        }
        if(ms != 0){
            sb.append(ms+"毫秒");
        }
        return sb.toString();
    }

    /**
     * 获取上周一到周天的日期
     *
     * @return {1：'2017-07-24',2:'2017-07-25'...}
     */
    public static Map<Integer,String> getBeforWeekDate(){

        Map<Integer,String> weekMap = new HashMap<>();
        // 日期格式转换
        SimpleDateFormat format = new SimpleDateFormat(CalendarUtil.SHORT_DATE_FORMAT);
        // 当前日期
        Calendar instance = Calendar.getInstance();
        // 调整到上周
        instance.add(Calendar.WEDNESDAY, -1);
        // 调整到上周1
        instance.set(Calendar.DAY_OF_WEEK, 2);
        //循环输出
        for (int i = 1; i <= 7; i++) {
            weekMap.put(i,format.format(instance.getTime()));
//            System.out.println("星期" + i + ":" + format.format(instance.getTime()));
            instance.add(Calendar.DAY_OF_WEEK, 1);
        }
        return weekMap;
    }

    public static String formatFullTime(long time) {
        String formatted = "";
        if (time != 0) {
            SimpleDateFormat sdf = new SimpleDateFormat(TIME_FULL_FORMAT);
            sdf.setTimeZone(TimeZone.getTimeZone("GMT+0"));//**TimeZone时区，加上这句话就解决啦**
            formatted = sdf.format(time);
        }
        return formatted;
    }

    /**
     * 计算时间差（单位：分钟）
     * @param start
     * @param end
     * @return
     */
    public static Long diffMinutes(Date start, Date end) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long diff = end.getTime() - start.getTime();
        //计算两个时间之间差了多少分钟
        Long minutes = diff / (1000 * 60);
        log.info("开始日期 start={}, 结束日期 end={}, 分钟数：{}" , start, end, diff);
        return minutes;
    }

    /**
     * 计算时间差（单位：小时）
     * 小数点后一位
     * @param start
     * @param end
     * @return
     */
    public static BigDecimal diffHours(Date start, Date end) {
        Long diffMinutes = diffMinutes(start, end);
        BigDecimal b1 = new BigDecimal(diffMinutes);
        BigDecimal b2 = new BigDecimal(60);
        return b1.divide(b2, 1, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 计算周几
     * @param date
     * @return
     */
    public static String getWeek(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEEE");
        String week = simpleDateFormat.format(date);
        log.info("日期 date={},星期：{}" , date, week);
        return week;
    }

    public static Date getCurrentHoursBefore(int i) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - i);
        return calendar.getTime();
    }

    public static Date getDateHoursBefore(Date date, int i) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - i);
        return calendar.getTime();
    }

    /**
     * 精确小数点后一位
     * @param seconds
     * @return
     */
    public static BigDecimal seconds2Minutes(Integer seconds) {
        BigDecimal b1 = new BigDecimal(seconds);
        BigDecimal b2 = new BigDecimal(60);
        return b1.divide(b2, 1, BigDecimal.ROUND_HALF_UP);
    }

    public static long getDayZeroTime(Date date)
    {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTimeInMillis();
    }

    public static void main(String[] args) {
        System.out.println(getCurrentHoursBefore(3));
    }
}
